
#include "ArchivoDeBloques.h"

using std::string;

ArchivoDeBloques::ArchivoDeBloques(string nombre, int sizeBloque)
{
	this->nombre = nombre;
	string arch(nombre+"."+ARCH_BLOQUES_EXT);

	if(!archivo.init(arch, ABRIR, sizeBloque))
		archivo.init(arch, CREAR, sizeBloque);

	administrador = new ListaEnlazada(nombre);

	bloqueActual = NULL;
	resetLectura();
}

ArchivoDeBloques::~ArchivoDeBloques()
{
	delete administrador;
}

int ArchivoDeBloques::agregarBloque(Bloque* bloque)
{
	int posicion = archivo.getCantBloques();
	agregarBloque(posicion,bloque);
	return posicion;
}

void ArchivoDeBloques::agregarBloque(int posicion, Bloque* bloque)
{
	char* serializado = bloque->serializar();
	archivo.writeBloque(posicion,serializado);
	delete[] serializado;
	resetLectura();
}

void ArchivoDeBloques::modificarBloque(int posicion, Bloque* bloque)
{
	agregarBloque(posicion,bloque);
}

string ArchivoDeBloques::getPath()
{
	return nombre;
}

int ArchivoDeBloques::getCantidadBloques()
{
	return archivo.getCantBloques();
}

int ArchivoDeBloques::getCantidadRegistros() {
	int cantDeRegsTotales = 0;

	for(int i=0; i<getCantidadBloques(); i++) {
		Bloque* bloque = obtenerBloque(i);
		cantDeRegsTotales += bloque->getCantidadRegistros();
		delete bloque;
	}

	return cantDeRegsTotales;
}

bool ArchivoDeBloques::quedanRegistros() {
	siguienteBloque();
	return nroBloqueActual < getCantidadBloques() || bloqueActual != NULL;
}

bool ArchivoDeBloques::siguienteRegistro(Registro* sig)
{
	siguienteBloque();

	if(bloqueActual != NULL) {
		Registro* reg = bloqueActual->desacolarRegistros();
		if(!bloqueActual->tieneRegistros()) {
			delete bloqueActual;
			bloqueActual = NULL;
			siguienteBloque();
		}
		sig->clonar(reg);
		delete reg;
		return true;
	}

	return false;
}

void ArchivoDeBloques::resetLectura() {
	nroBloqueActual = 0;
	if(bloqueActual != NULL) {
		delete bloqueActual;
		bloqueActual = NULL;
	}
}

void ArchivoDeBloques::siguienteBloque() {
	if(nroBloqueActual < getCantidadBloques() && bloqueActual == NULL) {
		bloqueActual = obtenerBloque(nroBloqueActual);
		nroBloqueActual++;
	}
}

Bloque* ArchivoDeBloques::obtenerBloque(int posicion)
{
	Bloque* bloque = new Bloque(archivo.getTamanioBloque());

	char* serial = archivo.readBloque(posicion);

	bloque->hidratar(serial);

	free(serial);

	return bloque;
}

void ArchivoDeBloques::setBloqueLibre(int posicionBloque)
{
	Bloque bloque(archivo.getTamanioBloque());

	modificarBloque(posicionBloque,&bloque);

	administrador->agregarBloqueLibre(posicionBloque);
}

int ArchivoDeBloques::getBloqueLibre()
{
	return administrador->pedirBloqueLibre();
}

void ArchivoDeBloques::limpiar()
{
	string path = archivo.getNombre();
	int sizeBloque = archivo.getTamanioBloque();

	archivo.close();
	archivo.init(path,CREAR,sizeBloque);
	resetLectura();
}
